package com.weike.yuanding.util;

import cn.hutool.json.JSONUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Redis 工具类，基于 Jedis 和 Hutool JSONUtil，支持常用的字符串、哈希、列表操作，
 * 并自动完成 JSON 序列化与反序列化。
 */
public class RedisUtil {

    private static final JedisPoolConfig POOL_CONFIG = buildPoolConfig();
    private static final JedisPool JEDIS_POOL = new JedisPool(POOL_CONFIG, "106.15.177.222", 6379 , 300000 ,"2225669369Yd.");
    private static final long DEFAULT_EXPIRE = 60 * 60 * 24; // 默认 1 天

    private static JedisPoolConfig buildPoolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(50);
        config.setMaxIdle(10);
        config.setMinIdle(2);
        config.setTestOnBorrow(true);
        config.setTestOnReturn(true);
        config.setTestWhileIdle(true);
        return config;
    }

    /**
     * 删除 Hash 中的一个或多个字段。
     *
     * @param key Redis 中的 Hash 键
     * @param fields 要删除的字段，可以是一个或多个
     */
    public static void hDel(String key, String... fields) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            jedis.hdel(key, fields);
        }
    }



    /**
     * 检查 Redis 中指定 Hash 的字段是否存在
     *
     * @param key   Redis 中的 Hash 键
     * @param field 要检查的字段名
     * @return 如果字段存在，返回 true；否则返回 false
     */
    public static boolean hExists(String key, String field) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.hexists(key, field);
        }
    }


    /**
     * 获取 Redis 中指定 Hash 的字段数量
     *
     * @param key Redis 中的 Hash 键
     * @return 字段数量，如果 key 不存在，返回 0
     */
    public static long hLen(String key) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.hlen(key);
        }
    }


    /**
     * 获取 Hash 下所有字段的值并反序列化为 List<T>；
     * 适用于所有字段的值均为 JSON 数组格式的场景，
     * 并按照字段名前缀的序号倒序排序。
     *
     * @param key         Redis 中的 Hash 键
     * @param elementType 列表元素的类型
     * @param <T>         列表元素泛型
     * @return 返回一个 Map，键为 Hash 字段名，值为对应的 List<T>（若字段值为空或不存在，则为空列表）
     */
    public static <T> Map<String, List<T>> hGetAllLists(String key, Class<T> elementType) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            // 取出所有字段及其 JSON 字符串值
            Map<String, String> entries = jedis.hgetAll(key);

            if (entries == null || entries.isEmpty()) {
                return new HashMap<>();
            }

            // 对字段按序号倒序排序
            List<Map.Entry<String, String>> sortedEntries = new ArrayList<>(entries.entrySet());
            sortedEntries.sort((e1, e2) -> {
                try {
                    long seq1 = Long.parseLong(e1.getKey().split("_")[0]);
                    long seq2 = Long.parseLong(e2.getKey().split("_")[0]);
                    return Long.compare(seq2, seq1); // 倒序
                } catch (NumberFormatException ex) {
                    return e2.getKey().compareTo(e1.getKey()); // 如果不是数字，按字段名字典倒序
                }
            });

            Map<String, List<T>> result = new LinkedHashMap<>(entries.size());
            // 遍历每个字段，反序列化为 List<T>
            for (Map.Entry<String, String> entry : sortedEntries) {
                String field = entry.getKey();
                String json = entry.getValue();
                if (json != null && !json.isEmpty()) {
                    result.put(field, JSONUtil.toList(JSONUtil.parseArray(json), elementType));
                } else {
                    result.put(field, new ArrayList<>());
                }
            }
            return result;
        }
    }


    /**
     * 存储对象，使用 JSON 格式化，并设置默认过期时间（1 天）。
     */
    public static <T> void set(String key, T value) {
        set(key, value, DEFAULT_EXPIRE, TimeUnit.SECONDS);
    }

    /**
     * 存储对象，使用 JSON 格式化，并设置过期时间。
     */
    public static <T> void set(String key, T value, long timeout, TimeUnit unit) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            String json = JSONUtil.toJsonStr(value);
            String set = jedis.set(key, json);
            jedis.expire(key, (int) unit.toSeconds(timeout));
        }
    }

    public static <T> List<T> getList(String key, Class<T> elementType) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            String json = jedis.get(key);
            if (json == null || json.isEmpty()) {
                return new ArrayList<>();
            }
            return JSONUtil.toList(JSONUtil.parseArray(json), elementType);
        }
    }

    /**
     * 获取 Hash 中字段值并反序列化为 List<T>；
     * 适用于字段值是 JSON 数组格式。
     * ai对话专用
     */
    public static <T> List<T> hGetList(String key, String field, Class<T> elementType) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            String json = jedis.hget(key, field);
            if (json == null || json.isEmpty()) {
                return new ArrayList<>();
            }
            return JSONUtil.toList(JSONUtil.parseArray(json), elementType);
        }
    }

    /**
     * 获取对象并反序列化为指定类型；若不存在返回 null。
     */
    public static <T> T get(String key, Class<T> clazz) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            String json = jedis.get(key);
            if (json == null || json.isEmpty()) {
                return null;
            }
            return JSONUtil.toBean(json, clazz);
        }
    }

    /**
     * 删除一个或多个 key。
     */
    public static void del(String... keys) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            jedis.del(keys);
        }
    }

    /**
     * 判断 key 是否存在。
     */
    public static boolean hasKey(String key) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.exists(key);
        }
    }

    /**
     * 自增，delta 要大于 0。
     */
    public static long incr(String key, long delta) {
        if (delta < 0) {
            throw new IllegalArgumentException("Delta must be positive");
        }
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.incrBy(key, delta);
        }
    }

    /**
     * 自减，delta 要大于 0。
     */
    public static long decr(String key, long delta) {
        if (delta < 0) {
            throw new IllegalArgumentException("Delta must be positive");
        }
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.decrBy(key, delta);
        }
    }

    /**
     * 普通 Map 存储为 Redis Hash，value 会被序列化为 JSON。
     */
    public static <T> boolean hmSet(String key, Map<String, T> map) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            Map<String, String> converted = new HashMap<>();
            map.forEach((field, val) -> converted.put(field, JSONUtil.toJsonStr(val)));
            String result = jedis.hmset(key, converted);
            return "OK".equals(result);
        }
    }

    /**
     * 普通 Map 存储为 Redis Hash，并设置过期时间。
     */
    public static <T> boolean hmSet(String key, Map<String, T> map, long timeout, TimeUnit unit) {
        boolean ok = hmSet(key, map);
        expire(key, timeout, unit);
        return ok;
    }

    /**
     * 获取整个 Hash 并反序列化所有 value。
     */
    public static <T> Map<String, T> hmGet(String key, Class<T> clazz) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            Map<String, String> entries = jedis.hgetAll(key);
            Map<String, T> result = new HashMap<>();
            entries.forEach((field, json) -> result.put(field, JSONUtil.toBean(json, clazz)));
            return result;
        }
    }

    /**
     * 获取 Hash 中单个 field。
     */
    public static <T> T hGet(String key, String field, Class<T> clazz) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            String json = jedis.hget(key, field);
            if (json == null) {
                return null;
            }
            return JSONUtil.toBean(json, clazz);
        }
    }

    /**
     * 设置 Hash 中单个 field。
     */
    public static <T> void hSet(String key, String field, T value) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            jedis.hset(key, field, JSONUtil.toJsonStr(value));
            jedis.expire(key, 8640000);
        }
    }

    /**
     * 列表 get，反序列化为指定类型。
     */
    public static <T> List<T> lGet(String key, long start, long end, Class<T> clazz) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            List<String> list = jedis.lrange(key, start, end);
            List<T> result = new ArrayList<>();
            for (String json : list) {
                result.add(JSONUtil.toBean(json, clazz));
            }
            return result;
        }
    }

    /**
     * 列表右推，并设置默认过期时间。
     */
    public static <T> long lPush(String key, T value) {
        return lPush(key, value, DEFAULT_EXPIRE, TimeUnit.SECONDS);
    }

    /**
     * 列表右推，并设置过期时间。
     */
    public static <T> long lPush(String key, T value, long timeout, TimeUnit unit) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            long size = jedis.rpush(key, JSONUtil.toJsonStr(value));
            jedis.expire(key, (int) unit.toSeconds(timeout));
            return size;
        }
    }

    /**
     * 获取 key 的剩余过期时间（秒）。
     */
    public static long ttl(String key) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.ttl(key);
        }
    }

    /**
     * 设置 key 的过期时间。
     */
    public static boolean expire(String key, long timeout, TimeUnit unit) {
        try (Jedis jedis = JEDIS_POOL.getResource()) {
            return jedis.expire(key, (int) unit.toSeconds(timeout)) == 1;
        }
    }

    // 私有构造，防止实例化
    private RedisUtil() {}
}
